<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport"
    content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    table {
      margin: 50px auto;
      padding: 0;
    }

    tr {
      margin: 0;
      padding: 0;
      display: block;
      height: 40px;
    }

    td {
      margin: 0;
      padding: 0;
      border: 1px solid #aaaaaa;
      box-sizing: border-box;
      width: 40px;
      height: 40px;
      float: left;
      text-align: center;
      line-height: 40px;
      position: relative;
      border-radius: 5px;
    }

    td::before {
      transition: background-color .2s ease-in-out;
    }

    .masking:before {
      display: block;
      position: absolute;
      left: 0;
      top: 0;
      content: '';
      width: 100%;
      height: 100%;
      background-color: #cccccc;
    }

    .warning:before {
      display: block;
      position: absolute;
      left: 0;
      top: 0;
      content: '';
      width: 100%;
      height: 100%;
      background-color: #d09b68;
    }
  </style>
</head>

<body>
  <table></table>
</body>
<script>
  //前置说明：type为整形标记，0为空白，1为雷，2为数字
  //递归空白算法
  function empty(i, j) {
    let now = table[i] && table[i][j];
    if (!now || now.type === 1 || now.className !== 'masking')
      return;
    now.className = '';
    if (now.type === 0) {
      empty(i - 1, j - 1);
      empty(i - 1, j);
      empty(i - 1, j + 1);
      empty(i, j - 1);
      empty(i, j + 1);
      empty(i + 1, j - 1);
      empty(i + 1, j);
      empty(i + 1, j + 1);
    }
  }

  //推断是否赢得比赛
  function compute() {
    let num = 0;
    for (i = 0; i < yNum; i++)
      for (j = 0; j < xNum; j++)
        if (table[i][j].className === 'masking' || table[i][j].className === 'warning')
          num++;
    return num === leiNum;
  }

  function gameover() {
    if (confirm('你失败了！重新开始？'))
      location.reload();
  }

  // 创建表格容器
  let dom = document.getElementsByTagName('table')[0];
  for (let i = 0; i < 15; i++) {
    let tr = document.createElement('tr');
    for (let j = 0; j < 15; j++) {
      tr.appendChild(document.createElement('td'));
    }
    dom.appendChild(tr);
  }
  let die = false;
  //找到所有格子
  let leiNum = 30;
  let xNum, yNum;
  let trs = document.getElementsByTagName('tr');
  yNum = trs.length;
  let table = [];
  for (let i = 0; i < yNum; i++) {
    let tds = trs[i].getElementsByTagName('td');
    xNum = tds.length;
    let tr = [];
    for (let j = 0; j < xNum; j++) {
      tds[j].type = 0;
      tds[j].pst = [i, j];
      tds[j].className = 'masking';
      tr.push(tds[j]);
    }
    table.push(tr);
  }
  //随机出雷的位置
  let leiObj = {};
  leiObj.length = 0;
  while (leiObj.length < leiNum) {
    let x = Math.floor(Math.random() * yNum);
    let y = Math.floor(Math.random() * xNum);
    if (!leiObj[x + '-' + y]) {
      leiObj[x + '-' + y] = [x, y];
      leiObj.length++;
    }
  }
  delete leiObj.length;
  let leis = [];
  for (let prop in leiObj) {
    leis.push(leiObj[prop]);
  }
  //埋雷
  for (i = 0; i < leiNum; i++) {
    let lei = leis[i];
    table[lei[0]][lei[1]].style.color = 'red';
    table[lei[0]][lei[1]].innerHTML = '雷';
    table[lei[0]][lei[1]].type = 1;
  }
  // 掀开附近空格子，标记雷数量
  for (i = 0; i < yNum; i++) {
    for (j = 0; j < xNum; j++) {
      if (table[i][j].type === 0) {
        let num = 0;
        if (table[i - 1] && table[i - 1][j - 1] && table[i - 1][j - 1].type === 1)
          num++;
        if (table[i - 1] && table[i - 1][j].type === 1)
          num++;
        if (table[i - 1] && table[i - 1][j + 1] && table[i - 1][j + 1].type === 1)
          num++;
        if (table[i][j - 1] && table[i][j - 1].type === 1)
          num++;
        if (table[i][j + 1] && table[i][j + 1].type === 1)
          num++;
        if (table[i + 1] && table[i + 1][j - 1] && table[i + 1][j - 1].type === 1)
          num++;
        if (table[i + 1] && table[i + 1][j].type === 1)
          num++;
        if (table[i + 1] && table[i + 1][j + 1] && table[i + 1][j + 1].type === 1)
          num++;
        table[i][j].innerHTML = num === 0 ? '' : num;
        table[i][j].type = num === 0 ? 0 : 2;
      }
    }
  }
  let tab = document.getElementsByTagName('table')[0];
  tab.oncontextmenu = function () {
    return false;
  };
  tab.addEventListener('mousedown', function (e) {
    let tar = e.target;
    if (e.button === 2) {
      if (tar.className === 'masking')
        tar.className = 'warning';
      else if (tar.className === 'warning')
        tar.className = 'masking';
    } else if (e.button === 0) {
      if (die) {
        gameover();
        return;
      }
      if (tar.className === 'warning')
        return;
      if (tar.type === 1) {
        die = true;
        for (i = 0; i < leiNum; i++) {
          let lei = leis[i];
          table[lei[0]][lei[1]].className = '';
        }
        setTimeout(function () {
          gameover();
        }, 300);
      } else {
        empty(tar.pst[0], tar.pst[1]);
        if (compute()) {
          setTimeout(function () {
            if (confirm('    6\n   666\n  66666\n 6666666\n666666666\n再来一局？'))
              location.reload();
          }, 300);
        }
      }
    }
  });
</script>

</html>